package com.beemans.admob.ads;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.LifecycleOwner;

import com.google.android.gms.ads.ResponseInfo;
import com.google.android.gms.ads.rewarded.RewardItem;

public class AbRewardAdvert extends AbBaseAdvert implements AbAdNetworkListener, AbRewardAdEventListener {
    @NonNull
    private final LifecycleOwner lifecycleOwner;
    @NonNull
    private final AbRewardAdvertConfig advertConfig;
    @Nullable
    private final FragmentActivity fragmentActivity;
    @Nullable
    private AbRewardAdvertCallback advertCallback;
    @Nullable
    private AbRewardAdWrapper adWrapper;

    private boolean isAdvertLoadFailed = false;

    public AbRewardAdvert(
            @NonNull LifecycleOwner lifecycleOwner,
            @NonNull AbRewardAdvertConfig advertConfig
    ) {
        this(lifecycleOwner, advertConfig, null);
    }

    public AbRewardAdvert(
            @NonNull LifecycleOwner lifecycleOwner,
            @NonNull AbRewardAdvertConfig advertConfig,
            @Nullable AbRewardAdvertCallback advertCallback
    ) {
        this.lifecycleOwner = lifecycleOwner;
        this.advertConfig = advertConfig;
        this.advertCallback = advertCallback;
        this.fragmentActivity = AdvertLifeUtils.getContext(lifecycleOwner);

        if (fragmentActivity == null) {
            return;
        }

        final String placementId = advertConfig.getPlacementId();
        adWrapper = AbAdvertLoadManager.getInstance().getRewardAdWrapper(placementId);

        AdvertLifeUtils.launchWhenDestroy(lifecycleOwner, this::onAdvertRelease);

        if (advertCallback != null) {
            advertCallback.onAdvertStart(this);
        }
    }

    @Override
    public boolean isAdvertReady() {
        if (adWrapper == null) {
            return false;
        }
        return adWrapper.isAdvertReady();
    }

    @Override
    public boolean isAdvertLoading() {
        if (adWrapper == null) {
            return false;
        }
        return adWrapper.isAdvertLoading();
    }

    @Override
    protected void loadAdvert() {
        loadAdvert(false);
    }

    @Override
    public void onAdvertRelease() {
        super.onAdvertRelease();

        if (advertCallback != null) {
            advertCallback = null;
        }
        if (adWrapper != null) {
            adWrapper = null;
        }
    }

    /**
     * @noinspection unused
     */
    private void loadAdvert(boolean isPreloadAdvert) {
        isAdvertLoadFailed = false;

        if (adWrapper == null) {
            return;
        }
        if (isAdvertReady()) {
            onAdvertLoaded();
            return;
        }

        setTimeout(advertConfig.getTimeoutMillis(), () -> {
            onAdvertLoadFail(AbAdvertConstants.ERR_TIMEOUT_DESC);
            onAdvertRelease();
        });

        waitForAdvertToLoad(() -> {
            if (isAdvertReady()) {
                onAdvertLoaded();
                return;
            }
            if (adWrapper != null && fragmentActivity != null) {
                adWrapper.loadAd(fragmentActivity, this);
            }
        });
    }

    /**
     * 展示广告
     */
    private void showAdvert() {
        if (fragmentActivity == null) {
            onAdvertShowFail();
            return;
        }

        AdvertLifeUtils.launchWhenResume(lifecycleOwner, () -> {
            if (!isAdvertReady()) {
                onAdvertShowFail();
                return;
            }
            if (adWrapper != null) {
                adWrapper.showAd(fragmentActivity, this);
            }
        });
    }

    private void onAdvertShowFail() {
        if (advertCallback != null) {
            advertCallback.onAdvertShowFail(this);
        }
    }

    private void onAdvertLoaded() {
        clearTimeout();

        if (advertCallback != null) {
            advertCallback.onAdvertLoaded(this);
        }
        if (advertConfig.isShowAfterLoaded()) {
            showAdvert();
        }
    }

    private void onAdvertLoadFail(String adError) {
        clearTimeout();

        if (isAdvertLoadFailed) return;
        isAdvertLoadFailed = true;

        if (advertCallback != null) {
            advertCallback.onAdvertLoadFail(this, adError);
        }
    }

    @Override
    public void onAdLoaded() {
        onAdvertLoaded();
    }

    @Override
    public void onAdFailedToLoad(@Nullable String loadAdError) {
        onAdvertLoadFail(loadAdError);
    }

    @Override
    public void onAdImpression(@Nullable ResponseInfo responseInfo) {
        if (advertCallback != null) {
            advertCallback.onAdvertRevenue(AbRewardAdvert.this, responseInfo);
        }
        if (advertCallback != null) {
            advertCallback.onAdvertShow(AbRewardAdvert.this, responseInfo);
        }
        if (advertConfig.isPreloadAdvert()) {
            final AbRewardAdvertConfig abRewardAdvertConfig
                    = AdvertGsonUtils.getInstance().deepClone(advertConfig, AbRewardAdvertConfig.class);
            if (abRewardAdvertConfig != null) {
                abRewardAdvertConfig.setShowAfterLoaded(false);

                final AbRewardAdvert rewardAdvert = new AbRewardAdvert(lifecycleOwner, abRewardAdvertConfig);
                rewardAdvert.loadAdvert(true);
            }
        }
    }

    @Override
    public void onAdDisplayFailed(@Nullable String adError) {
        onAdvertShowFail();
    }

    @Override
    public void onAdClicked(@Nullable ResponseInfo responseInfo) {
        if (advertCallback != null) {
            advertCallback.onAdvertClicked(AbRewardAdvert.this, responseInfo);
        }
    }

    @Override
    public void onAdClosed(@Nullable ResponseInfo responseInfo) {
        if (advertCallback != null) {
            advertCallback.onAdvertClose(AbRewardAdvert.this, responseInfo);
        }

        onAdvertRelease();
    }

    @Override
    public void onUserEarnedReward(@NonNull RewardItem rewardItem) {
        if (advertCallback != null) {
            advertCallback.onUserEarnedReward(AbRewardAdvert.this, rewardItem);
        }
    }
}